package data

import (
	"encoding/json"
	"io/ioutil"
	"net/url"
	"os"
	"strconv"
	"strings"
)

var Cache cache

type cache struct {
	SyntaxFile  []SyntaxFile             // 文件信息
	FileInfo    map[string]SyntaxApiList // 文件->接口信息
	ParamVal    map[string]cacheMap      // 参数信息
	ResultCache map[string]cacheMap      // 返回值信息
}

type cacheMap struct {
	Data map[string]interface{}
}

type SyntaxApiList struct {
	List []SyntaxApi
}

var paramValPath string
var resultCachePath string
func init() {
	paramValPath = "./runtime/param_val.json"
	resultCachePath = "./runtime/result_cache.json"

	if Cache.ParamVal == nil {
		Cache.ParamVal = map[string]cacheMap{}
	}
	if Cache.ResultCache == nil {
		Cache.ResultCache = map[string]cacheMap{}
	}
}

// 设置某文件的解析语法树
func(c *cache) SetSyntaxFile(syntaxFile SyntaxFile, syntaxApiList []SyntaxApi) {
	syntaxFile.SyntaxApiList = syntaxApiList
	has := false
	for k, v := range c.SyntaxFile {
		if v.FileName == syntaxFile.FileName {
			c.SyntaxFile[k] = syntaxFile
			has = true
		}
	}
	if !has {
		c.SyntaxFile = append(c.SyntaxFile, syntaxFile)
	}

	if c.FileInfo == nil {
		c.FileInfo = map[string]SyntaxApiList{}
	}
	c.FileInfo[syntaxFile.FileName] = SyntaxApiList{
		List: syntaxApiList,
	}
}

// 获取解析语法树文件列表
func (c *cache) GetSyntaxFileList() []SyntaxFile {
	return c.SyntaxFile
}

// 获取文件详情,也就是接口列表
func(c *cache) GetFileInfo(key string) []SyntaxApi {
	return c.FileInfo[key].List
}

// 根据具体url路径部分获取接口详情
func(c *cache) GetApiInfoByUrl(url string) SyntaxApi {
	// url article/index
	urlArr := strings.Split(url, "/")
	key := ""
	urlLen := len(urlArr)
	connector := ""
	for k, v := range urlArr {
		if urlLen - k == 1 {
			break
		}
		if k != 0 {
			connector = "/"
		}
		key += connector + v
	}

	apiList := c.GetFileInfo(key)
	for _, line := range apiList {
		if line.Url == url {
			return line
		}
	}
	return SyntaxApi{}
}

// 根据url添加参数,缓存起来
func(c *cache) AddParamByUrl(url string, post url.Values) {
	data := map[string]interface{}{}
	for k, v := range post {
		if k == "_method" || k == "_url" || k == "_urlfull" {
			continue
		}
		if len(v) > 0 {
			val, err := strconv.Atoi(v[0])
			if err != nil {
				data[k] = v[0]
			} else {
				data[k] = val
			}
		}
	}
	urlParam := cacheMap{
		Data: data,
	}
	if c.ParamVal == nil {
		c.ParamVal = map[string]cacheMap{}
	}
	c.ParamVal[url] = urlParam
}

// 根据url获取参数Key
func (c *cache) GetParamKeyByUrl(url string, key string) interface{} {
	param, ok := c.ParamVal[url]
	if !ok {
		return ""
	}
	val, ok := param.Data[key]
	if !ok {
		return ""
	}
	return val
}

// 根据url获取全部参数
func (c *cache) GetParamByUrl(url string) map[string]interface{} {
	param, ok := c.ParamVal[url]
	if !ok {
		return map[string]interface{}{}
	}
	return param.Data
}

// 根据url 获取结果字段描述,多个字段的列表
func(c *cache) GetResultCacheByUrl(url string) map[string]interface{} {
	res := map[string]interface{}{}
	data, ok := c.ResultCache[url]
	if !ok {
		return res
	}
	return data.Data
}

// 根据url.key添加结果字段描述
func (c *cache) AddResultCacheKeyByUrl(url string, key string, val string) {
	if c.ResultCache == nil {
		c.ResultCache = map[string]cacheMap{}
	}

	_, ok := c.ResultCache[url]
	if !ok {
		c.ResultCache[url] = cacheMap{
			Data: map[string]interface{}{},
		}
	}
	valInt, err := strconv.Atoi(val)
	if err != nil {
		c.ResultCache[url].Data[key] = val
	} else {
		c.ResultCache[url].Data[key] = valInt
	}
}

// 参数数据持久化
func(c *cache) ParamValPermanent() error {
	data := c.ParamVal
	datajson, err := json.Marshal(data)
	if err != nil {
		return err
	}

	err = ioutil.WriteFile(paramValPath, datajson, 0666)
	if err != nil {
		return err
	}
	return nil
}

// 结果描述持久化
func(c *cache) ResultCachePermanent() error {
	data := c.ResultCache
	datajson, err := json.Marshal(data)
	if err != nil {
		return err
	}

	err = ioutil.WriteFile(resultCachePath, datajson, 0666)
	if err != nil {
		return err
	}
	return nil
}

// 加载参数数据从持久化中
func(c *cache) LoadParamVal() error {
	_, err := os.Stat(paramValPath)
	if err != nil {
		return err
	}
	content, err := ioutil.ReadFile(paramValPath)
	if err != nil {
		panic(err)
	}


	paramVal := map[string]cacheMap{}
	err = json.Unmarshal(content, &paramVal)
	if err != nil {
		return err
	}

	c.ParamVal = paramVal
	return nil
}

// 加载参数数据从持久化中
func(c *cache) LoadResultCache() error {
	_, err := os.Stat(resultCachePath)
	if err != nil {
		return err
	}
	content, err := ioutil.ReadFile(resultCachePath)
	if err != nil {
		panic(err)
	}

	resultCache := map[string]cacheMap{}
	err = json.Unmarshal(content, &resultCache)
	if err != nil {
		return err
	}

	c.ResultCache = resultCache
	return nil
}